import asyncio
import threading
from typing import Tuple, Union
from playwright.async_api import async_playwright
from playwright.async_api._generated import BrowserContext, Page

class ThreadSafeList:
    def __init__(self):
        self._lock = threading.RLock()
        self._list = []

    def append(self, item):
        with self._lock:
            self._list.append(item)

    def remove(self, item):
        with self._lock:
            self._list.remove(item)

    def index(self, item):
        with self._lock:
            return self._list.index(item)
        
    def get(self, index):
        try:
            with self._lock:
                return self._list[index]
        except IndexError:
            return None



    def pop(self, index):
        with self._lock:
            return self._list.pop(index)
        
    def get_by_name(self, name):
        with self._lock:
            for item in self._list:
                if item["name"] == name:
                    return item 
        raise ValueError(f"Item with name {name} not found")
    class Iterator:
        def __init__(self, thread_safe_list):
            self._thread_safe_list = thread_safe_list
            self._lock = thread_safe_list._lock
            self._index = 0

        def __iter__(self):
            return self

        def __next__(self):
            with self._lock:
                if self._index < len(self._thread_safe_list):
                    current_index = self._index
                    self._index += 1
                    return self._thread_safe_list._list[current_index]
                else:
                    raise StopIteration

    def __iter__(self):
        return self.Iterator(self)

    def __len__(self):
        with self._lock:
            return len(self._list)

class BrowserSession:
    def __init__(self):
        self._browser = None
        self.safa_contexts = ThreadSafeList()
        self._loop = asyncio.get_event_loop()



    async def close(self):
        if self._context:
            await self._context.close()
        if self._browser:
            await self._browser.close()


    
    async def get_context(self, name: str):
        if len(self.safa_contexts) > 0:
            context = self.safa_contexts.get_by_name(name).get("context")
        else:
            context = await self.new_contex(name)
        return context
    
    async def new_contex(self, name: str):
        if self._browser is None:
            playwright = await async_playwright().start()
            self._browser = await playwright.chromium.launch(headless=False)

        context = await self._browser.new_context()
        context.safe_pages = ThreadSafeList()
        self.safa_contexts.append({"name": name, "context": context})
        return context
    
    async def get_page(self, context: BrowserContext, index: int=0) -> Tuple[Page, int]:
        page = context.safe_pages.get(index)
        if page:
            return page, index
        else:
            raise ValueError(f"Page with index {index} not found")
    
    async def new_page(self, context: BrowserContext):
        page = await context.new_page()
        context.safe_pages.append(page)
        index = context.safe_pages.index(page)
        return page, index
        

    async def close_page(self, context: BrowserContext, index):
        page = context.safe_pages.get(index)
        context.safe_pages.pop(index)
        await page.close()